use super::{
    analysis::{parse_params, DataLevel, ItemType},
    bar_line_chart::get_dfkb_name,
    RedisCache,
};
use crate::{get_big_table_column, BigTableColumn, Column};
use anyhow::Ok;
use shq_common::prelude::report::Unit;

pub(super) async fn create_pie_chart(
    rept_name: &str,
    params: &[(&str, &str)],
    leaf_cols: &[&Column],
    rept_unit: &Unit,
    tmp_table_name: &str,
) -> anyhow::Result<()> {
    let data_level = params
        .iter()
        .find(|(k, _)| *k == "data_level")
        .map(|(_, v)| *v)
        .ok_or(anyhow::anyhow!("报表{rept_name}的data_level参数不存在"))?;
    let data_level = DataLevel::try_from_str(data_level)?;
    let table_name = get_dfkb_name(data_level.clone());
    let cuid_where = if data_level == DataLevel::CompClie || data_level == DataLevel::IndiClie {
        let cuid = params
            .iter()
            .find(|(k, _)| *k == "cuid")
            .map(|(_, v)| *v)
            .ok_or(anyhow::anyhow!("cuid参数不存在"))?;
        let cuid: u64 = cuid
            .parse()
            .or_else(|_err| anyhow::bail!("参数cuid不是有效的整数"))?;
        format!("AND CUID={cuid}")
    } else {
        "".to_owned()
    };
    let (sdate, edate, _, col_name, item_type, level_cause, cyno_cause) = parse_params(params)?;
    let item_type = item_type.ok_or(anyhow::anyhow!("创建pie_chart失败，参数item_type不能为空"))?;
    let col = get_big_table_column(col_name).ok_or(anyhow::anyhow!(
        "报表{rept_name}，col_name:{col_name}不存在"
    ))?;
    let res = match item_type {
        ItemType::TPNO => {
            create_tpno_pie_chart(
                tmp_table_name,
                sdate,
                edate,
                col,
                level_cause,
                cyno_cause,
                &cuid_where,
                table_name,
                leaf_cols,
                rept_unit,
            )
            .await
        }
        ItemType::CYNO => {
            create_cyno_pie_chart(
                tmp_table_name,
                sdate,
                edate,
                col,
                level_cause,
                cyno_cause,
                &cuid_where,
                table_name,
                leaf_cols,
                rept_unit,
            )
            .await
        }
        ItemType::ITID => {
            create_pie_chart_with_type(
                tmp_table_name,
                sdate,
                edate,
                col,
                level_cause,
                cyno_cause,
                &cuid_where,
                "ITID",
                leaf_cols,
                rept_unit,
            )
            .await
        }
        ItemType::PERD => {
            create_pie_chart_with_type(
                tmp_table_name,
                sdate,
                edate,
                col,
                level_cause,
                cyno_cause,
                &cuid_where,
                "PERD",
                leaf_cols,
                rept_unit,
            )
            .await
        }
    };
    res.or_else(|err| anyhow::bail!("报表{rept_name},{}", err))?;
    Ok(())
}
async fn create_tpno_pie_chart(
    tmp_table_name: &str,
    sdate: &str,
    edate: &str,
    col: &BigTableColumn,
    level_cause: String,
    cyno_cause: &str,
    cuid_where: &str,
    table_name: &str,
    leaf_cols: &[&Column],
    rept_unit: &Unit,
) -> anyhow::Result<()> {
    let mut sql = format!(
        r#"WITH toDate('{sdate}') AS SDATE,toDate('{edate}') AS EDATE,dateDiff(day,SDATE,EDATE)+1 AS DAYS
    SELECT TPNM,SUM(AVVL) JE FROM ("#
    );
    match &col.classify_expr {
        crate::ClassifyExpr::Columns(items) => {
            let ilen = items.len();
            for (i, item) in items.iter().enumerate() {
                let ccol =
                    get_big_table_column(item).ok_or(anyhow::anyhow!("col_name:{item}不存在"))?;
                let one_sql = format!(
                    r#"SELECT '{}' AS TPNM,sum({item})/DAYS as AVVL
                FROM {table_name}
                where DTID>=SDATE and DTID<=EDATE {level_cause} {cyno_cause} {cuid_where}"#,
                    ccol.desc
                );
                sql.push_str(&one_sql);
                if i < ilen - 1 {
                    sql.push_str(" UNION ALL ");
                }
            }
        }
        crate::ClassifyExpr::Exp(exp) => {
            let tlen = col.df_tables.len();
            let dtid_col = col.dtid_col_name.as_str();
            let data_col = col.data_col_name.as_str();
            for (i, tname) in col.df_tables.iter().enumerate() {
                let one_sql = format!(
                    r#"SELECT {exp} AS TPNM,sum({data_col})/DAYS as AVVL
                FROM {tname}
                where {dtid_col}>=SDATE and {dtid_col}<=EDATE {level_cause} {cyno_cause}"#
                );
                sql.push_str(&one_sql);
                if i < tlen - 1 {
                    sql.push_str(" UNION ALL ");
                }
            }
        }
        crate::ClassifyExpr::None => anyhow::bail!("classify_expr没有配置，不能按照TPNO分类"),
    }
    sql.push_str(") T GROUP BY TPNM HAVING JE>0");
    RedisCache::new(tmp_table_name)?
        .cache(&sql, leaf_cols, rept_unit)
        .await?;
    Ok(())
}
async fn create_cyno_pie_chart(
    tmp_table_name: &str,
    sdate: &str,
    edate: &str,
    col: &BigTableColumn,
    level_cause: String,
    cyno_cause: &str,
    cuid_where: &str,
    table_name: &str,
    leaf_cols: &[&Column],
    rept_unit: &Unit,
) -> anyhow::Result<()> {
    let col_name = col.name.as_str();
    let sql = format!(
        r#"WITH toDate('{sdate}') AS SDATE,toDate('{edate}') AS EDATE,dateDiff(day,SDATE,EDATE)+1 AS DAYS,
         dictGet('DICT_CUCY','name',toUInt64(CYNO)) AS TPNM
    SELECT TPNM,sum({col_name})/DAYS as AVVL
    FROM {table_name}
    where DTID>=SDATE and DTID<=EDATE {level_cause} {cyno_cause} {cuid_where}
    GROUP BY CYNO
    HAVING AVVL>0"#
    );
    RedisCache::new(tmp_table_name)?
        .cache(&sql, leaf_cols, rept_unit)
        .await?;
    Ok(())
}
async fn create_pie_chart_with_type(
    tmp_table_name: &str,
    sdate: &str,
    edate: &str,
    col: &BigTableColumn,
    level_cause: String,
    cyno_cause: &str,
    cuid_where: &str,
    item_type: &str,
    leaf_cols: &[&Column],
    rept_unit: &Unit,
) -> anyhow::Result<()> {
    let dtid_col = col.dtid_col_name.as_str();
    let data_col = col.data_col_name.as_str();
    let (with_exp, group_by) = if item_type == "ITID" {
        let with_exp = if col.name.starts_with("ZS_") {
            "dictGet('DICT_MIDO_TYPE','ITNM',toUInt64(ITID)) AS TPNM"
        } else {
            "dictGet('DICT_ITEM','ITNM',toUInt64(ITID)) AS TPNM"
        };
        (with_exp, "ITID")
    } else if item_type == "PERD" {
        let with_exp = if col.name.starts_with("ZS_") {
            anyhow::bail!("字段col_name:{}为中收类，没有PERD的取数逻辑", col.name)
        } else {
            "dictGetString('DICT_PERD','RDNM',toUInt64(PERD)) AS TPNM"
        };
        (with_exp, "PERD")
    } else {
        anyhow::bail!("字段col_name:{}为中收类，没有PERD的取数逻辑", col.name)
    };
    let mut sql = format!(
        r#"WITH toDate('{sdate}') AS SDATE,toDate('{edate}') AS EDATE,dateDiff(day,SDATE,EDATE)+1 AS DAYS,{with_exp}
    SELECT TPNM,sum(AVVL) JE FROM ("#
    );
    let tlen = col.df_tables.len();
    for (i, tname) in col.df_tables.iter().enumerate() {
        let one_sql = format!(
            r#"SELECT {group_by},sum({data_col})/DAYS as AVVL
        FROM {tname}
        where {dtid_col}>=SDATE and {dtid_col}<=EDATE {level_cause} {cyno_cause} {cuid_where}
        group by {group_by}"#
        );
        sql.push_str(&one_sql);
        if i < tlen - 1 {
            sql.push_str("UNION ALL");
        }
    }
    sql.push_str(") T GROUP BY TPNM HAVING JE>0");
    RedisCache::new(tmp_table_name)?
        .cache(&sql, leaf_cols, rept_unit)
        .await?;
    Ok(())
}
